﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Globalization;
using AnyGrid.Properties;
using System.Web.Mvc;
using AnyGrid.Metadata;

namespace AnyGrid.Renderers
{
    public class BaseGridRenderer
    {
        protected static void AppendAnyGridClass(TagBuilder builder)
        {
            AppendClass(builder, "anyGrid");
        }

        protected static void AppendClass(TagBuilder builder, string className)
        {
            if (builder == null)
            {
                throw new ArgumentNullException("builder");
            }
            string cls;
            if (builder.Attributes.TryGetValue("class", out cls))
            {
                cls = cls + " " + className;
            }
            else
            {
                cls = className;
            }
            builder.Attributes["class"] = cls;
        }

        public static string IdColumn(ModelMetadata rowModelMetadata)
        {
            if (rowModelMetadata == null)
            {
                throw new ArgumentNullException("rowModelMetadata");
            }
            var keyAttrCol = rowModelMetadata.Properties.Where(p => p.AdditionalValues.Any(k => k.Key == AdditionalValuesKeys.IsKeyMember)).FirstOrDefault();
            if (keyAttrCol != null)
            {
                return keyAttrCol.PropertyName;
            }
            return rowModelMetadata.Properties.Where(p => p.PropertyName.Equals("Id", StringComparison.OrdinalIgnoreCase))
                                              .Select(p => p.PropertyName)
                                              .FirstOrDefault();
        }

        /// <summary>
        /// This method is used by AnyGridHtmlHelpers and should not typically be called by end-user code. 
        /// </summary>
        /// <param name="grids">A list of grids in the current HttpContext</param>
        /// <returns>Will return a script tag containing all necessary script for all grids on the page, 
        /// if any. The default implementation returns string.Empty. When overriding, implementers of 
        /// support for other grids should return a single script tag with appropriate JavaScript for 
        /// their grids.</returns>
        public static string RenderJavaScript(IEnumerable<GridViewModel> grids, ViewOptions options)
        {
            if (grids == null)
            {
                throw new ArgumentNullException("grids");
            }
            if (!grids.Any())
            {
                return string.Empty;
            }
            var gridJs = string.Join("\n", grids.Select(g => g.GridContext.ViewOptions.Renderer.RenderGridJavaScript(g)));
            var afterInitJs = (options != null
                                && options.AfterGridInitializationJavaScript != null) ?
                                options.AfterGridInitializationJavaScript
                                : string.Empty;
            if (string.IsNullOrEmpty(gridJs))
            {
                return string.Empty;
            }
            var tb = new TagBuilder("script");
            tb.MergeAttribute("type", "text/javascript");
            if (options != null && options.ScriptTagHtmlAttributes != null)
            {
                tb.MergeAttributes(options.ScriptTagHtmlAttributes);
            }
            tb.InnerHtml = gridJs + afterInitJs;
            return tb.ToString();
        }

        /// <summary>
        /// Developers who are implementing support for other grid components need to override this method 
        /// to return appropriate JavaScript for their grid. This method should return a script tag if 
        /// there are one or more grids in the grids argument which require scripting. 
        /// </summary>
        /// <param name="grids">A list of grids in the current HttpContext</param>
        /// <returns>Will return a script tag containing all necessary script for all grids on the page, 
        /// if any. The default implementation returns string.Empty. When overriding, implementers of 
        /// support for other grids should return a single script tag with appropriate JavaScript for 
        /// their grids.</returns>
        protected virtual string RenderGridJavaScript(GridViewModel grid)
        {
            return string.Empty;
        }

        /// <summary>
        /// This method is used by AnyGridHtmlHelpers and should not typically be called by end-user code. 
        /// Developers who are implementing support for other grid components need to override this method 
        /// to return appropriate HTML for their grid.
        /// </summary>
        /// <param name="grid">A presentation model containing information about the grid the rendered. 
        /// Information about page-specific options, IDs, etc., can be found in the GridContext property.</param>
        /// <param name="htmlAttributes">This argument may be null, or may contain additional attributes 
        /// specified by the end-user which should be merged into the grid's root-level tag.</param>
        /// <returns>An HTML fragment containing any number of HTML tags, as needed to render a single 
        /// instance of the grid. The default implementation returns string.Empty. When overriding, 
        /// implementers of support for other grids should return whatever in line markup is necessary to 
        /// render one grid.</returns>
        public virtual string RenderHtml(GridViewModel grid, IDictionary<string, object> htmlAttributes)
        {
            return string.Empty;
        }

        protected static TagBuilder TableTagBuilder(GridViewModel grid, IDictionary<string, object> htmlAttributes)
        {
            if (grid == null)
            {
                throw new ArgumentNullException("grid");
            }
            var tagBuilder = new TagBuilder("table");
            tagBuilder.MergeAttributes(htmlAttributes);
            tagBuilder.GenerateId(grid.GridContext.ViewOptions.GridHtmlId);
            AppendAnyGridClass(tagBuilder);
            return tagBuilder;
        }
    }
}
